#include <iostream>
#include <string>
#include <vector>
#include "Identifier.h"
#include "IdentifiersTable.h"
//tokens type
const int TOKEN_TYPE_INTEGER=-1;
const int TOKEN_TYPE_REAL=-2;
const int TOKEN_TYPE_STRING=-3;
const int TOKEN_TYPE_SINGLESYMBOL=-4;
const int TOKEN_TYPE_SPACE=-5;
const int TOKEN_TYPE_ENTER=-6;
const int LPAREN=35;
const int RPAREN=36;
const int LBRACKET=37;
const int RBRACKET=38;
const int LBRACE=39;
const int RBRACE=40;
const int COLON=41;
const int DOT=42;
const int SEMICOLON=43;
const int COMMA=44;
const int ASSIGN=45;
const int PLUS=46;
const int MINUS=47;
const int STAR=48;
const int SLASH=49;
const int BACKSLASH=50;
const int EQ=51;
const int NEQ=52;
const int LT=53;
const int LE=54;
const int GT=55;
const int GE=56;
const int LABRACKET=57;
const int RABRACKET=58;

#include "lex.yy.c"//This file should be included as a header file. Don't compile it as a source file otherwise it will be compiled twice.
std::string keywords[62]{ "identifier", "integer", "real","string","PROGRAM","IS","BEGIN","END","VAR",
"TYPE","PROCEDURE","ARRAY","RECORD","IN","OUT","READ","WRITE","IF","THEN","ELSE","ELSIF","WHILE",
"DO","LOOP","FOR","EXIT","RETURN","TO","BY","AND","OR","NOT","OF","DIV","MOD","(",")","[","]","{",
"}",":",".",";",",",":=","+","-","*","/","\\","=","<>","<","\"","<=",">",">=","[<",">]", "EOF", "ERROR" };
std::vector<std::string>types;
int main(int argc, char* arg[])
{
    IdentifiersTable identifiersTable();
    types.push_back("INTEGER");
    types.push_back("REAL");
    types.push_back("STRING");


    if(argc>1)
    {
        yyin=fopen(arg[1],"r");
    }
    int inputLine=1;
    int inputColumn=1;
	bool isComment = false;
	std::string previousToken = "";
    for(;;)
    {
        int tokenType=yylex();
        std::string tokenString(yytext);
	if(tokenString=="")
	{
		break;
	}
	if (isComment && tokenType != TOKEN_TYPE_SINGLESYMBOL)
	{
		if(tokenType!=TOKEN_TYPE_SPACE)
		{
                std::cout << "comment(" << tokenString << "),line " << inputLine << ",column " << inputColumn << std::endl;
		}
		inputColumn += tokenString.size();
		continue;
	}
        if(tokenType<0)
        {
            switch(tokenType)
            {
            case TOKEN_TYPE_INTEGER:
                std::cout<<"integer("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
                break;
            case TOKEN_TYPE_REAL:
                std::cout<<"real("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
                break;
            case TOKEN_TYPE_STRING:
                {
                    bool isKeyWord=false;
                    bool isType=false;
                    for(int i=0;i<62;++i)
                    {
                        if(tokenString==keywords[i])
                        {
                            isKeyWord=true;
                            break;
                        }
                    }
                    for(int i=0;i<types.size();++i)
                    {
                        if(tokenString==types[i])
                        {
                            isType=true;
                            break;
                        }
                    }
                    if(isKeyWord)
                    {
                        std::cout<<"keyword("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
                    }
                    else if(isType)
                    {
                        std::cout<<"type("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
                    }
                    else
                    {
                        //identifier
                        std::cout<<"identifier("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
                    }
                }
                break;
            case TOKEN_TYPE_SINGLESYMBOL:
                {
                    if(!isComment)
                    {
                        bool validSymbol=false;
                        for(int i=0;i<62;++i)
                        {
                            if(tokenString==keywords[i])
                            {
                                validSymbol=true;
                                break;
                            }
                        }
                        if(validSymbol)
                        {
                            std::cout<<"symbol("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
                        }
                        else
                        {
                            std::cout<<"syntax error:invalid symbol \""<<tokenString<<"\",line "<<inputLine<<",column "<<inputColumn<<std::endl;
                        }
                    }
                    else
                    {
                        //isComment
                        std::cout << "comment(" << tokenString << "),line " << inputLine << ",column " << inputColumn << std::endl;
                    }
		    if ((!isComment) && tokenString == "*" &&previousToken=="(")
		    {
			isComment = true;
			std::cout << "comment begin" << std::endl;
		    }
		    if (isComment && tokenString == ")" && tokenString == ")" && previousToken == "*")
		    {
			isComment = false;
			std::cout << "comment end" << std::endl;
		    }
                }
                break;
            case TOKEN_TYPE_SPACE:
                break;
            case TOKEN_TYPE_ENTER:
                ++inputLine;
                inputColumn=0;
                break;
            default:
                break;
            }
        }
        else
        {
            //tokenType>=0
            if(tokenType>=35)
            {
                std::cout<<"symbol("<<tokenString<<"),line "<<inputLine<<",column "<<inputColumn<<std::endl;
            }
            else
            {
                break;
            }
        }
        inputColumn+=tokenString.size();
	if(tokenType!=TOKEN_TYPE_SPACE)
	{
		previousToken = tokenString;
	}
    }
}
